﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using RPGXEngine.Factories;

namespace RPGXEngine.Networking
{
    public class MessageReader
    {
        #region Consts

        public const int MessageReadSizeInBytes = 1024;

        #endregion

        #region Call Backs

        public delegate void OnDisconnectDelegate();
        public event OnDisconnectDelegate OnDisconnect;

        #endregion

        #region Properties

        public byte[] Buffer
        {
            get { return _buffer; }
            set { _buffer = value; }
        }
        private byte[] _buffer = new byte[MessageReader.MessageReadSizeInBytes];

        public List<byte> TotalBuffer
        {
            get { return _totalBuffer; }
            set { _totalBuffer = value; }
        }
        private List<byte> _totalBuffer = new List<byte>();

        public delegate void ProcessMessageDelegate(NetworkMessage message);
        public event ProcessMessageDelegate ProcessMessage;

        public ILogger Logger
        {
            get { return _logger; }
            set { _logger = value; }
        }
        private ILogger _logger = null;

        #endregion

        #region Public Methods

        public MessageReader()
        {
            this.Logger = LoggerFactory.Get();
        }

        public void Read(NetworkStream stream)
        {
            stream.BeginRead(this.Buffer, 0, MessageReader.MessageReadSizeInBytes, new AsyncCallback(this.OnRead), stream);
        }

        #endregion

        #region Private Methods

        private void OnRead(IAsyncResult asy)
        {
            NetworkStream s = (NetworkStream)asy.AsyncState;

            try
            {
                int bytesRead = s.EndRead(asy);

                if (bytesRead == 0)
                {
                    s.Close();

                    if (this.OnDisconnect != null)
                        this.OnDisconnect();

                    return;
                }

                this.TotalBuffer.AddRange(this.Buffer.Take(bytesRead));

                while (s.DataAvailable)
                {
                    s.BeginRead(this.Buffer,
                        0,
                        MessageReader.MessageReadSizeInBytes,
                        this.OnRead,
                        s);
                }

                NetworkMessage m = NetworkMessageFactory.Create(this.TotalBuffer);

                this.TotalBuffer.Clear();

                if (this.ProcessMessage != null)
                    this.ProcessMessage(m);

                this.Read(s);
            }
            catch (Exception ex)
            {
                this.Logger.Log(String.Format("OnRead exception: {0}", ex.Message));

                s.Close();

                if (this.OnDisconnect != null)
                    this.OnDisconnect();
            }
        }

        private int GetMessageSize(byte[] bytes)
        {
            byte[] messageSize = new byte[sizeof(int)];
            for (int i = 0; i < sizeof(int); i++)
            {
                messageSize[i] = bytes[i];
            }

            return BitConverter.ToInt32(messageSize, 0);
        }

        #endregion
    }
}
